package multithreading;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.IntConsumer;

/**
 * @ClassName: FizzBuzz
 * @Description 1195. 交替打印字符串
 * 编写一个可以从 1 到 n 输出代表这个数字的字符串的程序，但是：
 *
 * 如果这个数字可以被 3 整除，输出 "fizz"。
 * 如果这个数字可以被 5 整除，输出"buzz"。
 * 如果这个数字可以同时被 3 和 5 整除，输出 "fizzbuzz"。
 * 例如，当n = 15，输出：1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz。
 *
 * @Author skywingking
 * @Date 2021/11/19 9:57 下午
 **/
public class FizzBuzz {
    private int n;
    private Lock lock;
    private int i = 1;
    private Condition condition;

    public FizzBuzz(int n) {
        this.n = n;
        this.lock = new ReentrantLock();
        this.condition = lock.newCondition();
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        lock.lock();
        try{
            while(i <= n){
                if(i % 3 == 0 && i % 5 != 0){
                    printFizz.run();
                    i++;
                    condition.signalAll();
                }else{
                    //Fizz线程等待
                    condition.await();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        lock.lock();
        try{
            while(i <= n){
                if(i % 5 == 0 && i % 3 != 0){
                    printBuzz.run();
                    i++;
                    condition.signalAll();
                }else{
                    //Buzz线程等待
                    condition.await();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        lock.lock();
        try{
            while(i <= n){
                if(i % 3 == 0 && i % 5 == 0){
                    printFizzBuzz.run();
                    i++;
                    condition.signalAll();
                }else{
                    //FizzBuzz线程等待
                    condition.await();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        lock.lock();
        try{
            while(i <= n){
                if(i % 3 != 0 && i % 5 != 0){
                    printNumber.accept(i);
                    i++;
                    condition.signalAll();
                }else{
                    //Number线程等待
                    condition.await();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}